package com.vainycos.lotterysearch.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vainycos.lotterysearch.enums.ExceptionEnum;
import com.vainycos.lotterysearch.exception.BusinessException;
import com.vainycos.lotterysearch.mapper.BigLotteryBallMapper;
import com.vainycos.lotterysearch.model.BigLotteryBall;
import com.vainycos.lotterysearch.model.ro.BigLotteryRo;
import com.vainycos.lotterysearch.service.notify.DingNotify;
import com.vainycos.lotterysearch.service.notify.MailNotify;
import com.vainycos.lotterysearch.tool.GetLottery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

/**
 * @author: Vainycos
 * @description 大乐透开奖服务类
 * @date: 2022/11/3 16:50
 */
@Slf4j
@Service
public class BigLotteryService extends ServiceImpl<BigLotteryBallMapper, BigLotteryBall> {

    @Resource
    private BigLotteryBallMapper bigLotteryBallMapper;

    @Lazy
    @Autowired
    private MailNotify mailNotify;

    @Lazy
    @Autowired
    private DingNotify dingNotify;

    @Value("${receive.mail-address:}")
    private String receiveMailAddress;

    /**
     * 全量新增开奖信息
     * @return
     */
    public boolean batchInsertInit (){
        // 判断如果数据库有数据则提示需清空之后再全量同步
        BigLotteryBall bigLotteryBall = bigLotteryBallMapper.selectOne(new LambdaQueryWrapper<BigLotteryBall>().last("limit 1"));
        if (bigLotteryBall != null){
            throw new BusinessException(ExceptionEnum.BATCH_INIT);
        }
        List<BigLotteryBall> allBLB = GetLottery.getAllBLB();
        log.info("扫描到超级大乐透开奖信息总共{}条, 开始全量更新...", allBLB.size());
        return this.saveBatch(allBLB);
    }

    /**
     * 增量同步
     * @return
     */
    public boolean syncInsert(){
        // 获取最近一期
        BigLotteryBall bigLotteryBall = searchLatestBigLottery();
        if (bigLotteryBall == null){
            // 数据库尚未初始化数据，进行全量更新
            log.info("超级大乐透尚未初始化数据，进行全量更新...");
            return batchInsertInit();
        }
        // 获取最近期号之后的开奖情况
        List<BigLotteryBall> laterBLB = GetLottery.getLaterBLB(bigLotteryBall.getPeriodId());
        if (laterBLB.size() == 0){
            throw new BusinessException(ExceptionEnum.SYNC_INSERT);
        }
        log.info("获取到超级大乐透增量开奖信息{}条, 开始增量同步...", laterBLB.size());
        boolean saveBatch = this.saveBatch(laterBLB);
        log.info("增量同步成功!");
        mailNotify.mailNotifyBigLotteryBall(laterBLB, Arrays.asList(receiveMailAddress));
        dingNotify.notifyBigLotteryBall(laterBLB);
        return saveBatch;
    }

    /**
     * 查询最近一期开奖清空
     * @return
     */
    public BigLotteryBall searchLatestBigLottery(){
        // 获取最近的一条记录
        LambdaQueryWrapper<BigLotteryBall> query = new LambdaQueryWrapper<>();
        query.orderByDesc(BigLotteryBall::getPeriodId);
        query.last("limit 1");
        return bigLotteryBallMapper.selectOne(query);
    }

    /**
     * 根据期数查询单期开奖情况
     * @param periodId
     * @return
     */
    public BigLotteryBall getBLBBySinglePeriodId(int periodId){
        LambdaQueryWrapper<BigLotteryBall> query = new LambdaQueryWrapper<>();
        query.eq(BigLotteryBall::getPeriodId, periodId);
        return bigLotteryBallMapper.selectOne(query);
    }

    /**
     * 获取该期之后的开奖情况
     * @param periodId
     * @return
     */
    public List<BigLotteryBall> getLaterBLB(int periodId){
        LambdaQueryWrapper<BigLotteryBall> query = new LambdaQueryWrapper<>();
        query.gt(BigLotteryBall::getPeriodId, periodId);
        query.orderByAsc(BigLotteryBall::getPeriodId);
        return bigLotteryBallMapper.selectList(query);
    }

    /**
     * 前区号码历史中奖率， 前区号码匹配量/历史开奖量
     * @param frontAreaNum
     * @return
     */
    public String historyFrontArea(int frontAreaNum){
         return bigLotteryBallMapper.historyFrontArea(frontAreaNum);
    }

    /**
     * 后区号码历史中奖率， 前区号码匹配量/历史开奖量
     * @param endAreaNum
     * @return
     */
    public String historyEndArea(int endAreaNum){
        return bigLotteryBallMapper.historyEndArea(endAreaNum);
    }

    /**
     * 中奖规则：
     * 5红+2蓝 一等奖
     * 5红+1蓝 二等奖
     * 5红 / 4红+2蓝 三等奖
     * 4红+1蓝 / 3红+2蓝 四等奖 200元
     * 4红 / 3红+1蓝 / 2红+2蓝 五等奖 10元
     * 3红 / 2红+1蓝 / 1红+2蓝 2蓝  六等奖 5元
     * @param bigLotteryRo 输入号码
     * @param bigLottoBall 开奖号码
     * @return
     */
    public int matchLevelPrizes(BigLotteryRo bigLotteryRo, BigLotteryBall bigLottoBall){
        List<Integer> redBullList = Arrays.asList(bigLottoBall.getRedBallOne(),
                bigLottoBall.getRedBallTwo(),
                bigLottoBall.getRedBallThree(),
                bigLottoBall.getRedBallFour(),
                bigLottoBall.getRedBallFive()
        );
        List<Integer> blueBullList = Arrays.asList(bigLottoBall.getBlueBallOne(), bigLottoBall.getBlueBallTwo());

        // 红球中奖计数
        int redBallCount = 0;
        // 蓝球中奖计数
        int blueBallCount = 0;
        redBallCount += redBullList.contains(bigLotteryRo.getRedBallOne()) ? 1 : 0;
        redBallCount += redBullList.contains(bigLotteryRo.getRedBallTwo()) ? 1 : 0;
        redBallCount += redBullList.contains(bigLotteryRo.getRedBallThree()) ? 1 : 0;
        redBallCount += redBullList.contains(bigLotteryRo.getRedBallFour()) ? 1 : 0;
        redBallCount += redBullList.contains(bigLotteryRo.getRedBallFive()) ? 1 : 0;

        blueBallCount += blueBullList.contains(bigLotteryRo.getBlueBallOne()) ? 1 : 0;
        blueBallCount += blueBullList.contains(bigLotteryRo.getBlueBallTwo()) ? 1 : 0;

        boolean level6 = (redBallCount == 3 && blueBallCount == 0) || (redBallCount == 2 && blueBallCount == 1) || (redBallCount == 1 && blueBallCount == 2) || (redBallCount == 0 && blueBallCount == 2);
        boolean level5 = (redBallCount == 4 && blueBallCount == 0) || (redBallCount == 3 && blueBallCount == 1) || (redBallCount == 2 && blueBallCount == 2);
        boolean level4 = (redBallCount == 4 && blueBallCount == 1) || (redBallCount == 3 && blueBallCount == 2);
        boolean level3 = (redBallCount == 5 && blueBallCount == 0) || (redBallCount == 4 && blueBallCount == 2);
        boolean level2 = (redBallCount == 5 && blueBallCount == 1);
        boolean level1 = (redBallCount == 5 && blueBallCount == 2);
        if (level6){
            return 6;
        }else if (level5){
            return 5;
        }else if (level4){
            return 4;
        }else if (level3){
            return 3;
        }else if (level2){
            return 2;
        }else if (level1){
            return 1;
        }else {
            // 异常未匹配情况
            return 0;
        }

    }

    /**
     * 根据中奖情况输出兑奖描述
     * @param resultBigLotteryBall 开奖情况
     * @param bigLotteryRo 用户号码
     * @return
     */
    public String describeByPrice(BigLotteryBall resultBigLotteryBall, BigLotteryRo bigLotteryRo){
        StringBuffer result = new StringBuffer();
        result.append("期号：" + resultBigLotteryBall.getPeriodId() + "。"
                + "开奖日期：" + resultBigLotteryBall.getLotteryDate() + "。"
                + "开奖号码：" + resultBigLotteryBall.winnerResult() + "。"
                + "您的号码：" + bigLotteryRo.inputNumberResult() + "。");
        int i = matchLevelPrizes(bigLotteryRo, resultBigLotteryBall);
        if (i > 0){
            result.append("恭喜您中奖了，中了" + i + "等奖");
        }else {
            result.append("不好意思您未中奖，希望下次好运");
        }
        return result.toString();
    }

    /**
     * 仅输出开奖情况
     * @param resultBigLotteryBall 开奖情况
     * @return
     */
    public String describe(BigLotteryBall resultBigLotteryBall){
        StringBuffer result = new StringBuffer();
        result.append("期号：" + resultBigLotteryBall.getPeriodId() + "。"
                + "开奖日期：" + resultBigLotteryBall.getLotteryDate() + "。"
                + "开奖号码：" + resultBigLotteryBall.winnerResult() + "。");
        return result.toString();
    }

    /**
     * 仅输出开奖情况
     * @param resultBigLotteryBall 开奖情况
     * @return
     */
    public String describeForMarkdown(String subject, BigLotteryBall resultBigLotteryBall){
        String result =
//                "> " + FreeApiUtil.dailyWord() + " \n" +
                "## [幸运小助手]提醒您：" + subject + " \n" +
                "开奖号码：" + resultBigLotteryBall.winnerResult() + "\n" +
                "![counting-money-in-the-dark](https://gitee.com/dearvainycos/my-pic/raw/master/img/counting-money-in-the-dark.jpg)";
        return result;
    }
}
